iT邦幫忙

2024 iThome 鐵人賽

DAY 2
0
佛心分享-刷題不只是刷題

Leecode刷題系列 第 2

D1:Q2 Add Two Numbers

  • 分享至 

  • xImage
  •  

先理解題目要求
題目給我兩個非空的鏈結串列,每個節點表是一個數字,這些數字是「倒序」存儲的。目標是把兩個數字相加,然後返回結果當成新的鏈結串列。就是要模擬一個「按位相加」的過程,類似在紙上手動計算兩個多位數的數字相加。

關鍵:鏈結串列是倒序存儲的,所以可以像從右到左相加一樣,從鏈結串列的頭開始遍歷,輸入兩個鏈結串列,代表兩個數字再輸出一個新鏈結串列,代表兩個數字的和。

分解問題
目標是把兩個數字相加,可以分解出幾個小問題來解決:
遍歷兩個鏈結串列,需要從頭開始遍歷兩個鏈結串列,在每一步取出對應節點的數字,按位相加,取出兩個節點的數字,計算它們的總和,然後考慮是否有進位,然後就是處理進位,如果相加的結果超過 9,就需要把進位保留,然後再把進位加到下一位的加法裡,之後再建新鏈結串列,每次計算出一位的結果時,把結果存到新的鏈結串列中,再繼續處理直到兩個鏈結串列都處理完。

設計解法
想像一個常見的「虛擬頭節點」以此來簡化鏈結串列的操作。這樣就不用特別處理頭節點的特殊情況,最後只要返回這個虛擬頭節點的下一個節點就可以了,所以需要初始化一個虛擬頭節點,再設置一個變數 carry 來保存進位,遍歷兩個鏈結串列,在每一步,取出兩個鏈結串列的節點值,如果節點為空就取 0,計算當前位的總和把節點值相加,再加上 carry,如果結果大於 9,進位保存在 carry 中,建一個新節點儲存當前位的結果,然後把當前指標移到下一個節點繼續遍歷,如果其中一個鏈結串列較短,可以把短的部分補 0 繼續運算。

考慮特殊情況
鏈結串列長度不同,如果一個鏈結串列比另一個短時,可以把短的部分當作 0 來處理,這樣不會有問題,最後還有進位,在鏈結串列遍歷完之後,可能還會有一個進位沒有處理,這就需要再創一個新節點來存儲這個進位。

開始寫程式
。用迴圈遍歷兩個鏈結串列
。每次計算當前位數的和與進位
。動態地建新的鏈結串列來儲存加法結果

想法
題目的關鍵點在按位相加、進位處理以跟鏈結串列操作,把問題分解成遍歷鏈結串列、計算進位和結果、跟動態建構新鏈結串列三個部分,就可以一步步地解決這個問題。
https://ithelp.ithome.com.tw/upload/images/20240915/20169309kebPUgOqm7.png
構思 技巧
鏈結串列的操作:學到怎麼用 Python 操作鏈結串列,理解怎樣處理「節點」跟它們之間的「連結」,然後就是進位處理,這裡展示麼在進行加法時處理進位,這在處理二進位、十進位等各種加法都很有用,還有條件邏輯,在處理鏈結串列長度不一樣時,用 if l1 else 0 這種條件來靈活應對,這樣就比較不會有錯誤訊息。把加法運算封裝在addTwoNumbers 中,在解決更大問題時把邏輯分解成小步驟(模組化的思考方式)可以更好的處理解決問題。
這段程式碼練習基本的資料結構操作、邏輯判斷、和進位運算等 Python 的基本技巧,讓我可以更清楚了解Python 這門程式語言的用法。

程式碼:
#定義單向鏈結串列的節點類別
class ListNode(object):
def init(self, val=0, next=None):
self.val = val
self.next = next

class Solution(object):
def addTwoNumbers(self, l1, l2):
"""
:type l1: ListNode
:type l2: ListNode
:rtype: ListNode
"""
#初始化虛擬節點以及指向結果的指標
dummy = ListNode(0)
current = dummy
carry = 0 # 用於進位

#遍歷兩個鏈結串列
while l1 or l2 or carry:
#取出當前節點的值,若節點為空則取值為 0
val1 = l1.val if l1 else 0
val2 = l2.val if l2 else 0

#計算當前位的總和與進位
total = val1 + val2 + carry
carry = total // 10 # 計算進位
total = total % 10 # 計算當前位的值

#建立新節點儲存當前的值
current.next = ListNode(total)
current = current.next # 移動到下一個節點

#繼續遍歷鏈結串列
if l1:
l1 = l1.next
if l2:
l2 = l2.next

#返回結果鏈結串列(虛擬節點的下一個)
return dummy.next

心得:
第一題說實話,一開始要挑戰這個連續三十天不間斷寫程式學習新東西開頭都讓人覺得很煩躁,但是開始了就不能斷,所以只能硬著頭皮逼自己盡量不要中斷(現在超後悔暑假不多屯一點文 哭~)
這個 Leetcode 題目 "Add Two Numbers" 主要用處是讓我對 Python 的理解跟怎麼處理鏈結串列、進位運算、和程式邏輯更加熟悉。

因為鏈結串列是一種很基本但蠻重要的資料結構,跟一般的陣列不同的地方在鏈結串列的節點是通過指標相互連接,這就表示操作起來需要更加謹慎,在這題,我學會怎樣從鏈結串列裏每ㄧ個節點取值,然後進行進位相加,過程讓我了解了節點之間的關係和怎麼在 Python 中進行動態記憶體的操作。

另一個外收穫是進位的處理(我一開始很不理解它用倒敘是怎麼一回事 搞超久)。如果兩個節點相加大於 9 ,下一位會連帶進位,這是一個很常見的運算問題,不論是在數字的加減還是其他進位制計算,進位處理都是一個很容易被忽略或是出錯的問題,這題我透過 carry = total // 10 和 total = total % 10 這樣的算法,了解怎樣把進位跟當前位數字分開,然後把進位傳到下一位數。

這題還有條件邏輯的運用,在處理鏈結串列的長度不一樣的情況下,用 if l1 else 0 這樣的條件運算可以讓我靈活應對各種情況,免去程式錯誤或崩潰的狀況,這讓我體會到寫程式的容錯性是真的很重要。

以上最主要就是讓我了解鏈結串列的操作和進位運算,再來就是怎麼才能寫出更簡潔、有效、且具容錯能力的程式碼,其實解出這題,不算太困難因此讓我對 Python 的應用有比較多信心,至少不會這麼早就想放棄,希望我之後遇到演算法的問題也能順利解決。


上一篇
Leetcode刷題計畫表
下一篇
D4:Q16
系列文
Leecode刷題10
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言